package me.stone.stanimeclient.core.ui.helpers

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.net.ConnectivityManager
import android.net.Network
import android.net.NetworkCapabilities
import android.net.NetworkInfo
import android.net.NetworkRequest
import android.os.Build
import android.telephony.TelephonyManager
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
import androidx.lifecycle.lifecycleScope
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.distinctUntilChangedBy
import kotlinx.coroutines.flow.stateIn
import kotlinx.coroutines.launch
import me.stone.stanimeclient.core.common.extensions.grantedSelfPermissions
import me.stone.stanimeclient.core.common.utils.WhileViewSubscribed
import me.stone.stanimeclient.core.model.NetworkMode
import timber.log.Timber

class NetworkStateHelper(private val activity: AppCompatActivity) {

    companion object {
        private const val CONFIG_DEBUG_LOG = false
        private fun d(log: String) {
            if (CONFIG_DEBUG_LOG) Timber.d(log)
        }
    }

    private val currentMode: NetworkMode
        get() {
            val connManager = connManager ?: return NetworkMode.None
            val networkState = connManager.activeNetworkInfo?.state ?: return NetworkMode.None
            return when (networkState) {
                NetworkInfo.State.CONNECTED, NetworkInfo.State.CONNECTING -> NetworkMode.Wifi
                else -> getNetworkType()
            }.also { d("current mode: $it") }
        }

    private val _networkMode by lazy { MutableStateFlow(currentMode)  }

    val networkModeFlow: StateFlow<NetworkMode>
        get() = _networkMode
            .distinctUntilChangedBy { it }
            .stateIn(activity.lifecycleScope, WhileViewSubscribed, currentMode)

    private val _grantPermission by lazy { MutableStateFlow(checkPermissions()) }

    val grantPermission: StateFlow<Boolean>
        get() = _grantPermission
            .distinctUntilChangedBy { it }
            .stateIn(activity.lifecycleScope, WhileViewSubscribed, checkPermissions())

    private val permissions = if (Build.VERSION.SDK_INT > Build.VERSION_CODES.TIRAMISU) arrayOf(
        Manifest.permission.READ_PHONE_STATE,
        Manifest.permission.READ_BASIC_PHONE_STATE
    ) else arrayOf(Manifest.permission.READ_PHONE_STATE)

    private val perReqLauncher = activity.registerForActivityResult(
        ActivityResultContracts.RequestMultiplePermissions()
    ) { permissions ->
        val grantAllPermissions = permissions.entries.all { it.value }
        d("on result all grant: $grantAllPermissions")
        if (grantAllPermissions) {
            activity.lifecycleScope.launch {
                _networkMode.emit(currentMode)
            }
        }
        activity.lifecycleScope.launch {
            _grantPermission.emit(grantAllPermissions)
        }
    }

    private val connManager by lazy {
        activity.getSystemService(Context.CONNECTIVITY_SERVICE) as? ConnectivityManager
    }

    private val telephonyManager by lazy {
        activity.getSystemService(Context.TELEPHONY_SERVICE) as? TelephonyManager
    }

    private val networkCallback: ConnectivityManager.NetworkCallback by lazy {
        object : ConnectivityManager.NetworkCallback() {
            override fun onCapabilitiesChanged(
                network: Network,
                networkCapabilities: NetworkCapabilities
            ) {
                var validate = networkCapabilities
                    .hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)
                if (!validate && Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                    validate = networkCapabilities
                        .hasCapability(NetworkCapabilities.NET_CAPABILITY_VALIDATED)
                }

                if (!validate) {
                    d("network not validate")
                    activity.lifecycleScope.launch {
                        _networkMode.emit(NetworkMode.None)
                    }
                    return
                }

                val wifi = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI)
                if (wifi) {
                    d("network conn is wifi")
                    activity.lifecycleScope.launch {
                        _networkMode.emit(NetworkMode.Wifi)
                    }
                    return
                }

                val cellular = networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR)
                if (cellular) {
                    d("network conn is cellular")
                    activity.lifecycleScope.launch {
                        _networkMode.emit(getNetworkType())
                    }
                    return
                }

                activity.lifecycleScope.launch {
                    _networkMode.emit(NetworkMode.None)
                }
            }
        }
    }

    @SuppressLint("MissingPermission")
    private fun getNetworkType(): NetworkMode {
        if (!activity.grantedSelfPermissions(permissions)) {
            d("can not get telephone manager")
            return NetworkMode.None
        }

        d("network type get success?")
        val networkType = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            telephonyManager?.dataNetworkType
        } else {
            telephonyManager?.networkType
        } ?: return NetworkMode.None
        d("network type get success")

        return when (networkType) {
            // 2G 网络判断
            TelephonyManager.NETWORK_TYPE_GPRS,
            TelephonyManager.NETWORK_TYPE_CDMA,
            TelephonyManager.NETWORK_TYPE_EDGE,
            TelephonyManager.NETWORK_TYPE_1xRTT -> NetworkMode.Mode2G
            // 3G 网络判断
            TelephonyManager.NETWORK_TYPE_EVDO_0,
            TelephonyManager.NETWORK_TYPE_EVDO_A,
            TelephonyManager.NETWORK_TYPE_EVDO_B,
            TelephonyManager.NETWORK_TYPE_UMTS,
            TelephonyManager.NETWORK_TYPE_HSPA,
            TelephonyManager.NETWORK_TYPE_HSUPA,
            TelephonyManager.NETWORK_TYPE_HSDPA,
            TelephonyManager.NETWORK_TYPE_HSPAP,
            TelephonyManager.NETWORK_TYPE_EHRPD -> NetworkMode.Mode3G
            // 4G 网络判断 (19 最大仅到SDK30)
            TelephonyManager.NETWORK_TYPE_LTE, 19 -> NetworkMode.Mode4G
            // 5G 网络判断
            TelephonyManager.NETWORK_TYPE_NR -> NetworkMode.Mode5G
            else -> NetworkMode.None
        }.also { d("network type is $it") }
    }

    init {
        activity.lifecycle.addObserver(object : DefaultLifecycleObserver {
            override fun onResume(owner: LifecycleOwner) {
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                    connManager?.registerDefaultNetworkCallback(networkCallback)
                } else {
                    connManager?.registerNetworkCallback(
                        NetworkRequest.Builder().build(),
                        networkCallback
                    )
                }
            }

            override fun onPause(owner: LifecycleOwner) {
                connManager?.unregisterNetworkCallback(networkCallback)
            }
        })
    }

    private fun checkPermissions(): Boolean {
        return activity.grantedSelfPermissions(permissions)
    }

    fun requestPermissionsAndTry() {
        perReqLauncher.launch(permissions)
    }

}